#pragma once

#include "IPayload.h"

namespace RoomFW {

//
// Class : SendMessageError
//
// Description : Error thrown by an ActiveObject when sendMessage() fails.
//
class SendMessageError : public ErrorHandling::BaseError
{ 
public: 
	//
	// Reason for failure
	//
	enum Reason
	{
		SMER_NONE,					// No error.
		SMER_INVALID_PORT,			// Invalid port index.
		SMER_PORT_NOT_BOUND,		// Valid port index, but not bound.
		SMER_RECEIVER_ERRORED,		// The recipient of the message is in an errored state.
		SMER_BROADCAST_PAYLOAD,		// Attempt to broadcast a payload.  Not allowed.
		SMER_BROADCAST_INVOKE,		// Attempt to broadcast an invoke.  Not allowed.
		SMER_CONTRACT_VIOLATION,	// Message does not comply with contract (protocol) specified port's protocol.
		SMER_REPLY_TO_REPLY,		// Attempt to reply to a message that was sent by reply.  Not allowed.
		SMER_INVOKE_TIMEOUT,		// An invoke timed out and the call specified (or defaulted) to handle it with an exception.
		SMER_COUNT	// MUST BE LAST VALUE!!!  Number of errors.  Used for testing.
	};

	SendMessageError(const char* sourceObjectName,
					 const PortIndex& portIndex,
					 MessageID messageId,
					 IPayloadSP payload,
					 Reason reason);
	SendMessageError(const PortIndex& portIndex,
					 MessageID messageId,
					 IPayloadSP payload,
					 Reason reason);
	virtual ~SendMessageError();
	virtual void raise() {throw *this;}
	virtual ErrorHandling::IErrorSP clone() const throw() {return ErrorHandling::IErrorSP(new SendMessageError(*this));}
	virtual const char* getName() const throw();
	virtual std::string toString() const throw();
	virtual std::string getDescription() const throw();
	static const char* ReasonText(const Reason reason);

	// Accessors.
	PortIndex getPortIndex();
	MessageID getMessageId();
	IPayloadSP getPayload();
	IPayloadSP releasePayload();
	Reason getReason();
	void setObjectName(const char* objectName);
	void setPortIndexText(const char* portIndexText);
	void setMessageIdText(const char* messageIdText);

private:
	PortIndex portIndex_;
	MessageID messageId_;
	IPayloadSP payload_;
	Reason reason_;
	std::string portIndexText_;
	std::string messageIdText_;

	// The default ctor and other items below provide support for boost serialization
	SendMessageError::SendMessageError()
		:
		BaseError(ErrorHandling::EID_FND_SEND_MESSAGE, ErrorHandling::ESEVsoftwareWarning),
		portIndex_(PortIndex()),
		messageId_(INVALID_MESSAGE_ID),
		payload_(IPayloadSP()),
		reason_(Reason())
	{
	}

	friend class boost::serialization::access;
	template<class Archive>
	void serialize(Archive & ar, const unsigned int file_version)
	{
		boost::serialization::base_object<SpiFoundation::ErrorHandling::BaseError>(*this);
		ar & portIndex_;
		ar & messageId_;
#if 0	
		// The following line will cause a compilation error "Error	1	error C2027: use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'..."
		// According to ...\boost\include\boost\serialization\shared_ptr.hpp
		//		correct shared_ptr serialization depends upon object tracking being used.
		ar & payload_;
#endif
		ar & reason_;
		ar & portIndexText_;
		ar & messageIdText_;
	}
};
typedef ::boost::shared_ptr<SendMessageError> SendMessageErrorSP;

} // end namespace ErrorHandling

